#ifndef __ACTIONS_QUEUER_H__
#define __ACTIONS_QUEUER_H__

#include <list>
#include <assert.h>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>

template<class Item>
struct IActionCallback
{
    virtual ~IActionCallback() { }
    virtual void DoAction(Item* packet) throw() = 0;
};

template<class Item>
class CActionsQueuer : private boost::noncopyable
{
public:
    CActionsQueuer(IActionCallback<Item>* pCallback);
    ~CActionsQueuer();
    
public:
    void Push(Item* packet);
    
private:
    void Worker();
    bool IsWorkFinish();

private:
    IActionCallback<Item>* m_pCallback;
    std::list<Item> m_container;
    
    boost::thread m_worker;
    boost::mutex m_containerLock;
    boost::condition_variable m_fullCondition;

    boost::mutex m_stopLock;
    boost::condition_variable m_stopCondition;
    bool m_finish;
};

template<class Item>
bool CActionsQueuer<Item>::IsWorkFinish()
{
    boost::unique_lock<boost::mutex> l(m_stopLock);

    if (m_finish)
    {
        m_stopCondition.notify_all();
    }
    return m_finish;
}
//////////////////////////////////////////////////////////////////////////

template<class Item>
void CActionsQueuer<Item>::Worker()
{
    for(;;)
    {
        boost::unique_lock<boost::mutex> l(m_containerLock);
        m_fullCondition.wait(l);
        
        if(IsWorkFinish())
            return;

        while(!m_container.empty())
        {
            Item outBuffer;
            outBuffer.swap(m_container.front());
            m_container.pop_front();

            l.unlock();
            m_pCallback->DoAction(&outBuffer);
            l.lock();
            
            if(IsWorkFinish())
                return;
        }
    }

}

template<class Item>
void CActionsQueuer<Item>::Push( Item* packet )
{
    boost::unique_lock<boost::mutex> l(m_containerLock);
    
    if(packet)
        m_container.push_back(*packet);

    m_fullCondition.notify_all();
}

template<class Item>
CActionsQueuer<Item>::~CActionsQueuer()
{
    boost::unique_lock<boost::mutex> l(m_stopLock);
    
    m_finish = true;
    Push(NULL);

    m_stopCondition.wait(l);
}

template<class Item>
CActionsQueuer<Item>::CActionsQueuer( IActionCallback<Item>* pCallback )
: m_pCallback(pCallback)
, m_finish(false)
, m_worker(&CActionsQueuer<Item>::Worker, this)
{
    assert(pCallback);
}

#endif
